﻿using System;
using System.Collections;
using System.Web;
using System.Text;
using System.IO;
using System.Runtime.Caching;
using System.Diagnostics;
using System.Runtime.Serialization.Formatters.Binary;
using System.Configuration;
using System.Collections.Generic;
using Newtonsoft.Json;
using System.Text.Json.Serialization;

namespace FieldTools.Util
{
    /// <summary>
    /// 缓存对象数据结构
    /// </summary>
    [Serializable()]
    public class CacheData
    {
        public object Value { get; set; }
        public DateTime CreateTime { get; set; }
        public DateTimeOffset AbsoluteExpiration { get; set; }
        public DateTime FailureTime
        {
            get
            {
                if (AbsoluteExpiration == ObjectCache.InfiniteAbsoluteExpiration)
                {
                    return AbsoluteExpiration.DateTime;
                }
                else { return CreateTime.AddTicks(AbsoluteExpiration.Ticks); }
            }
        }
        public CacheItemPriority Priority { get; set; }
    }

    /// <summary>
    /// 缓存处理类(MemoryCache)，缓存存入文件
    /// </summary>
    public class CacheHelper
    {
        /// <summary>
        /// 在应用程序的同级目录(主要防止外部访问)
        /// </summary>
        public static string filePath = Path.GetFullPath(AppDomain.CurrentDomain.BaseDirectory + "/cache/");

        /// <summary>
        /// 文件扩展名
        /// </summary>
        public static string fileExt = ".cache";
        /// <summary>
        /// 获取数据缓存
        /// </summary>
        /// <param name="cacheKey">键</param>
        public static object GetCache(string cacheKey)
        {
            //System.Web.Caching.Cache objCache = HttpRuntime.Cache;
            //return objCache[cacheKey];
            long i = MemoryCache.Default.GetCount();
            CacheItem objCache = MemoryCache.Default.GetCacheItem(cacheKey);
            if (objCache == null)
            {
                string _filepath = filePath + cacheKey + fileExt;
                if (File.Exists(_filepath))
                {
                    FileStream _file = File.OpenRead(_filepath);
                    if (_file.CanRead)
                    {
                        Debug.WriteLine("缓存反序列化获取数据：" + cacheKey);
                        object obj = BinaryDeSerialize(_file);
                        CacheData _data = (CacheData)obj;
                        if (_data != null)
                        {
                            //判断是否过期
                            if (_data.FailureTime >= DateTime.Now)
                            {
                                //将数据添加到内存
                                SetCacheToMemory(cacheKey, _data);
                                return _data.Value;
                            }
                            else
                            {
                                Debug.WriteLine("数据过期：" + cacheKey);
                                File.Delete(_filepath);
                                //数据过期
                                return null;
                            }
                        }
                        else { return null; }
                    }
                    else { return null; }
                }
                else { return null; }
            }
            else
            {
                CacheData _data = (CacheData)objCache.Value;
                return _data.Value;
            }
        }
        /// <summary>
        /// 获取缓存
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="cacheKey"></param>
        /// <returns></returns>
        public static T? GetCache<T>(string cacheKey)
        {
            var cache = GetCache(cacheKey);
            if(cache != null)
            {
                return JsonConvert.DeserializeObject<T>(cache.ToString());
            }
            else return default;
        }
        /// <summary>
        /// 内存缓存数
        /// </summary>
        /// <returns></returns>
        public static object GetCacheCount()
        {
            return MemoryCache.Default.GetCount();
        }
        /// <summary>
        /// 获取所有内存缓存
        /// </summary>
        /// <returns></returns>
        public static Dictionary<string, object> GetMemoryCacheAll()
        {
            var _cache = MemoryCache.Default;
            var res = new Dictionary<string, object>();
            foreach (var _c in _cache.GetValues(null))
            {
                res.Add(_c.Key, _c.Value);
            }
            return res;
        }
        /// <summary>
        /// 获取所有文件缓存，且将文件缓存挂载至内存，过期自动删除
        /// </summary>
        /// <returns></returns>
        public static Dictionary<string, object> GetFileCacheAll()
        {
            DirectoryInfo di = new(filePath);
            if (!di.Exists) return new();
            var files = di.GetFiles();
            var res = new Dictionary<string, object>();
            foreach (var file in files)
            {
                var _file = File.OpenRead(file.FullName);
                if (_file.CanRead)
                {
                    object obj = BinaryDeSerialize(_file);
                    CacheData _data = (CacheData)obj;
                    if (_data != null)
                    {
                        var key = Path.GetFileNameWithoutExtension(file.Name);
                        string _filepath = filePath + key + fileExt;
                         res.Add(key, _data);
                        //判断是否过期，暂不处理过期情况
                        if (_data.FailureTime >= DateTime.Now)
                        {
                            //将数据添加到内存
                            SetCacheToMemory(key, _data);
                        }
                        else
                        {
                            File.Delete(_filepath);
                            //数据过期
                            return null;
                        }
                    }
                }
            }
            return res;
        }
        /// <summary>
        /// 文件缓存数
        /// </summary>
        /// <returns></returns>
        public static object GetFileCacheCount()
        {
            DirectoryInfo di = new DirectoryInfo(filePath);
            return di.GetFiles().Length;
        }

        /// <summary>
        /// 设置数据缓存
        /// </summary>
        public static bool SetCache(string cacheKey, string objObject, CacheItemPolicy policy)
        {
            string _filepath = filePath + cacheKey + fileExt;
            if (Directory.Exists(filePath) == false)
            {
                Directory.CreateDirectory(filePath);
            }
            //设置缓存数据的相关参数
            CacheData data = new CacheData() { Value = objObject, CreateTime = DateTime.Now, AbsoluteExpiration = policy.AbsoluteExpiration, Priority = policy.Priority };
            CacheItem objCache = new CacheItem(cacheKey, data);
            FileStream stream = null;
            if (File.Exists(_filepath) == false)
            {
                stream = new FileStream(_filepath, FileMode.CreateNew, FileAccess.Write, FileShare.Write);
            }
            else
            {
                stream = new FileStream(_filepath, FileMode.Create, FileAccess.Write, FileShare.Write);
            }
            Debug.WriteLine("缓存序列化设置数据：" + cacheKey);
            BinarySerialize(stream, data);
            try
            {
                MemoryCache.Default.Set(objCache, policy);
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }
        /// <summary>
        /// 设置缓存，不存文件
        /// </summary>
        /// <param name="cacheKey"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        public static bool SetCacheToMemory(string cacheKey, CacheData data)
        {
            CacheItemPolicy policy = new CacheItemPolicy();
            CacheItem objCache = new CacheItem(cacheKey, data);
            policy.AbsoluteExpiration = data.AbsoluteExpiration;
            policy.Priority = CacheItemPriority.NotRemovable;
            try
            {
                MemoryCache.Default.Set(objCache, policy);
                return true;
            }
            catch (Exception)
            {
                return false;
            }
            
        }
        /// <summary>
        /// 设置缓存，指定有效时间
        /// </summary>
        /// <param name="cacheKey"></param>
        /// <param name="objObject"></param>
        /// <param name="AbsoluteExpiration"></param>
        /// <returns></returns>
        public static bool SetCache(string cacheKey, string objObject, DateTimeOffset AbsoluteExpiration)
        {
            CacheItemPolicy _priority = new CacheItemPolicy();
            _priority.Priority = CacheItemPriority.NotRemovable;
            _priority.AbsoluteExpiration = AbsoluteExpiration;
            return SetCache(cacheKey, objObject, _priority);
        }
        public static bool SetCache<T>(string cacheKey, T objObject, DateTimeOffset AbsoluteExpiration)
        {
            return SetCache(cacheKey, JsonConvert.SerializeObject(objObject), AbsoluteExpiration);
        }
        /// <summary>
        /// 设置缓存，指定缓存策略
        /// </summary>
        /// <param name="cacheKey"></param>
        /// <param name="objObject"></param>
        /// <param name="priority"></param>
        /// <returns></returns>
        public static bool SetCache(string cacheKey, string objObject, CacheItemPriority priority)
        {
            CacheItemPolicy _priority = new CacheItemPolicy();
            _priority.Priority = priority;
            _priority.AbsoluteExpiration = ObjectCache.InfiniteAbsoluteExpiration;
            return SetCache(cacheKey, objObject, _priority);
        }
        public static bool SetCache<T>(string cacheKey, T objObject, CacheItemPriority priority)
        {
            return SetCache(cacheKey, JsonConvert.SerializeObject(objObject), priority);
        }
        /// <summary>
        /// 设置数据缓存
        /// </summary>
        public static bool SetCache(string cacheKey, string objObject)
        {
            return SetCache(cacheKey, objObject, CacheItemPriority.NotRemovable);
        }

        /// <summary>
        /// 设置数据缓存
        /// </summary>
        public static bool SetCache<T>(string cacheKey, T objObject)
        {
            return SetCache(cacheKey, JsonConvert.SerializeObject(objObject), CacheItemPriority.NotRemovable);
        }

        /// <summary>
        /// 移除指定数据缓存
        /// </summary>
        public static void RemoveCache(string cacheKey)
        {
            MemoryCache.Default.Remove(cacheKey);
            string _filepath = filePath + cacheKey + fileExt;
            File.Delete(_filepath);
        }

        /// <summary>
        /// 移除全部缓存
        /// </summary>
        public static void RemoveAllCache()
        {
            MemoryCache _cache = MemoryCache.Default;
            foreach (var _c in _cache.GetValues(null))
            {
                _cache.Remove(_c.Key);
            }
            DirectoryInfo di = new DirectoryInfo(filePath);
            di.Delete(true);
        }
        /// <summary>
        /// 清除指定缓存
        /// </summary>
        /// <param name="type">1:内存 2:文件</param>
        public static void RemoveAllCache(int type)
        {
            if (type == 1)
            {
                MemoryCache _cache = MemoryCache.Default;
                foreach (var _c in _cache.GetValues(null))
                {
                    _cache.Remove(_c.Key);
                }
            }
            else if (type == 2)
            {
                DirectoryInfo di = new DirectoryInfo(filePath);
                di.Delete(true);
            }
        }
        /// <summary>
        /// 获取缓存，没有时候存入
        /// </summary>
        /// <param name="cacheKey"></param>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static T GetOrSetCache<T>(string cacheKey, T obj)
        {
            var temp = GetCache(cacheKey);
            try
            {
                return JsonConvert.DeserializeObject<T>(temp.ToString());
            }
            catch (Exception ex)
            {
                SetCache(cacheKey, JsonConvert.SerializeObject(obj));
                return obj;
            }
        }
        /// <summary>
        /// 获取缓存，没有时候存入
        /// </summary>
        /// <param name="cacheKey"></param>
        /// <param name="obj"></param>
        /// <param name="AbsoluteExpiration"></param>
        /// <returns></returns>
        public static T GetOrSetCache<T>(string cacheKey, T obj, DateTimeOffset AbsoluteExpiration = new DateTimeOffset())
        {
            var temp = GetCache(cacheKey);
            try
            {
                return JsonConvert.DeserializeObject<T>(temp.ToString());
            }
            catch (Exception ex)
            {
                SetCache(cacheKey, JsonConvert.SerializeObject(obj), AbsoluteExpiration);
                return obj;
            }
        }

        #region 配置导入、导出
        /// <summary>
        /// 导出配置
        /// </summary>
        /// <param name="cacheKey"></param>
        /// <param name="filePath"></param>
        public static void ExportCache(string cacheKey, string filePath)
        {
            try
            {
                var json = GetCache(cacheKey).ToString();
                //SaveFileDialog sfd = new SaveFileDialog();
                //sfd.Title = "";
                //sfd.InitialDirectory = @"C:\";
                //sfd.Filter = "文本文件| *.txt";
                //sfd.ShowDialog();

                //string path = sfd.FileName;
                //if (path == "")
                //{
                //    return;
                //}
                if(!string.IsNullOrEmpty(json)) json.SaveToFile(filePath);
            }
            catch (Exception)
            {

                throw;
            }
        }

        /// <summary>
        /// 导入配置
        /// </summary>
        /// <param name="cacheKey"></param>
        /// <param name="filePath"></param>
        public static void ImportCache(string cacheKey, string filePath)
        {
            try
            {
                if(File.Exists(filePath))
                {
                    var json = File.ReadAllText(filePath);
                    SetCache(cacheKey, json);
                }
            }
            catch (Exception)
            {

                throw;
            }
        }
        #endregion

        #region 流序列化
        public static void BinarySerialize(Stream stream, object obj)
        {
            try
            {
                stream.Seek(0, SeekOrigin.Begin);
                BinaryFormatter formatter = new BinaryFormatter();
                formatter.Serialize(stream, obj);
            }
            catch (Exception e)
            {
                //IOHelper.WriteDebug(e);
            }
            finally
            {
                //stream.Close();
                stream.Dispose();
            }
        }

        public static object BinaryDeSerialize(Stream stream)
        {
            object obj = null;
            stream.Seek(0, SeekOrigin.Begin);
            try
            {
                BinaryFormatter formatter = new BinaryFormatter();
                obj = formatter.Deserialize(stream);
            }
            catch (Exception e)
            {
                //IOHelper.WriteDebug(e);
            }
            finally
            {
                //stream.Close();
                stream.Dispose();
            }
            return obj;
        }
        #endregion
    }
}